<?
/** 
*   Class controls the logging of error or debug information
*	@class  	CLog
*   @version 	1.0
*	@file  		CLog.php
*	@author		Rolf Wessels rolfdw[at]gmail.com
*	$Revision: 1.2 $
* 	License: LGPL, see LICENSE

Simple example:
---------------
if ((12 + 12) == 24) CLog::error("This is correct ??? ",__FILE__,__LINE__);

// output 
// 2006-06-30 02:48:37 : *** ERROR   This is correct ??? (F-D:\folder\CLog.php)    (#-13)

**/




////////////////////
// General settings
if (!defined('CLOG_OVERRIDE_ERROR_HANDLER')) define('CLOG_OVERRIDE_ERROR_HANDLER',true);  // will display normal errors using this class
if (!defined('CLOG_ALLOW_SENDING_EMAIL')) define('CLOG_ALLOW_SENDING_EMAIL',false);
if (!defined('CLOG_SEND_EMAIL_TO')) define('CLOG_SEND_EMAIL_TO',"info@fu.bar");

////////////////////
// The levels of warnings/errors
if (!defined('CLOG_DEBUG')) 		define('CLOG_DEBUG',"090");
if (!defined('CLOG_NOTICE')) 		define('CLOG_NOTICE',"100");
if (!defined('CLOG_WARNING')) 		define('CLOG_WARNING',"200");
if (!defined('CLOG_ERROR')) 		define('CLOG_ERROR',"300");
if (!defined('CLOG_FATAL')) 		define('CLOG_FATAL',"400");

////////////////////
// Where to save the files
if (!defined('CLOG_LOG_FILE_NAME'))    	define('CLOG_LOG_FILE_NAME',date("Y-m")."_error_php.log");
if (!defined('CLOG_LOG_FILE_PATH')) 	define('CLOG_LOG_FILE_PATH',"c:\\logs\\"); // remember to add a trailing slash
if (!defined('CLOG_LOG_FILE_DEBUG')) 	define('CLOG_LOG_FILE_DEBUG',CLOG_LOG_FILE_NAME);
if (!defined('CLOG_LOG_FILE_NOTICE')) 	define('CLOG_LOG_FILE_NOTICE',CLOG_LOG_FILE_NAME);
if (!defined('CLOG_LOG_FILE_WARNING')) 	define('CLOG_LOG_FILE_WARNING',CLOG_LOG_FILE_NAME);
if (!defined('CLOG_LOG_FILE_ERROR')) 	define('CLOG_LOG_FILE_ERROR',CLOG_LOG_FILE_NAME);
if (!defined('CLOG_LOG_FILE_FATAL')) 	define('CLOG_LOG_FILE_FATAL',CLOG_LOG_FILE_NAME);


////////////////////
// This defines the levels at which the loggin should take place
if (!defined('CLOG_LVL_DISPLAY_LEVEL')) define('CLOG_LVL_DISPLAY_LEVEL',CLOG_NOTICE); // errors from level XX to be displayed on screen
if (!defined('CLOG_LVL_WRITE_TO_FILE')) define('CLOG_LVL_WRITE_TO_FILE',CLOG_ERROR); // errors from level XX to be logged to file
if (!defined('CLOG_LVL_EMAIL')) define('CLOG_LVL_EMAIL',CLOG_ERROR); // errors from level XX to be emailed to recipients



////////////////////
// Format the date for logging
if (!defined('CLOG_DEFAULT_DATE_FORMAT')) 		define('CLOG_DEFAULT_DATE_FORMAT',"Y-m-d");
if (!defined('CLOG_DEFAULT_TIME_FORMAT')) 		define('CLOG_DEFAULT_TIME_FORMAT',"H:i:s");
if (!defined('CLOG_DEFAULT_DATETIME_FORMAT')) 	define('CLOG_DEFAULT_DATETIME_FORMAT',CLOG_DEFAULT_DATE_FORMAT.' '.CLOG_DEFAULT_TIME_FORMAT);

class CLog
{
	/**
	* Stores level of current error
	* @var int
	*/ 
	var $m_level =  CLOG_DEBUG;
	/**
	* Stores file Name of current error
	* @var string
	*/ 
	var $m_fileName = "" ;
	/**
	* Stores line Number of current error
	* @var int
	*/ 
	var $m_lineNumber = "0" ;
	/**
	* Stores last Error description
	* @var string
	*/ 
	var $m_lastErrorString = "";
	
    /****************************************************************************************
    * CONSTRUCTOR 
    *****************************************************************************************/
	function CLog()
	{
		
	}
	
	/****************************************************************************************
	* Static functions
	*****************************************************************************************/
	
	/**
	* Static function to add a notice log
	* @access public
	* @return void 
	**/
	function notice($in_errstr , $in_errfile = NULL, $in_errline  = NULL)
	{
		$log = new Clog();
		$log->set_level(CLOG_NOTICE);
		$log->set_fileName($in_errfile);
		$log->set_lineNumber($in_errline);
		$log->log($in_errstr);
	}
	
	/**
	* Static function to add a debug log
	* @access public
	* @return void 
	**/
	function debug($in_errstr , $in_errfile = NULL, $in_errline  = NULL)
	{
		
		$log = new Clog();
		$log->set_level(CLOG_DEBUG);
		$log->set_fileName($in_errfile);
		$log->set_lineNumber($in_errline);
		$log->log($in_errstr);
	}
	
	/**
	* Static function to add a warning log
	* @access public
	* @return void 
	**/
	function warning($in_errstr , $in_errfile = NULL, $in_errline  = NULL)
	{
		$log = new Clog();
		$log->set_level(CLOG_WARNING);
		$log->set_fileName($in_errfile);
		$log->set_lineNumber($in_errline);
		$log->log($in_errstr);
	}
	/**
	* Static function to add an error log
	* @access public
	* @return void 
	**/
	function error($in_errstr , $in_errfile = NULL, $in_errline  = NULL)
	{
		$log = new Clog();
		$log->set_level(CLOG_ERROR);
		$log->set_fileName($in_errfile);
		$log->set_lineNumber($in_errline);
		$log->log($in_errstr);
	}
	
	/**
	* Static function to add a fatal error and stops the program/script
	* @access public
	* @return void 
	**/
	function fatal($in_errstr , $in_errfile = NULL, $in_errline  = NULL)
	{
		$log = new Clog();
		$log->set_level(CLOG_FATAL);
		$log->set_fileName($in_errfile);
		$log->set_lineNumber($in_errline);
		$log->log($in_errstr);
		die();
	}
	/****************************************************************************************
	* Main functions
	*****************************************************************************************/
	
	/**
	* Main logging function
	* @access public
	* @return void 
	**/
	function log($in_errstr)
	{
		
		$this->m_lastErrorString = $in_errstr;
		
		if ($this->m_level >= CLOG_LVL_DISPLAY_LEVEL)
		{
			$this->display_error();
		}
		if ($this->m_level >= CLOG_LVL_WRITE_TO_FILE)
		{
			$this->log_to_file();
		}
		if (CLOG_ALLOW_SENDING_EMAIL && $this->m_level >= CLOG_LVL_EMAIL)
		{
			$this->email_error();
		}
				
	}
	
	/**
	* Displays this error/log to screen
	* @access 	private
	* @return 	void
	* @author 	Rolf Wessels rolfdw[at]gmail.com
	**/
	function display_error()
	{
			echo '<div class=error>'.$this->get_levelName().'
				  <div >'."\n";
			echo ($this->m_lastErrorString);
			if (!empty($this->m_fileName) )
			echo "<br> File: ".$this->m_fileName;
			if (!empty($this->m_lineNumber) )
		 	echo "&nbsp;&nbsp;  (#$this->m_lineNumber)";
			echo '</div></div>';
	}
	
	/**
	* Write the error to file
	* @access 	private
	* @return 	void
	* @author 	Rolf Wessels rolfdw[at]gmail.com
	**/
	function log_to_file()
	{
		$line = date(CLOG_DEFAULT_DATETIME_FORMAT)." : *** ".str_pad($this->get_levelName(),8);
		$line .= $this->m_lastErrorString;
		
		if (!empty($this->m_fileName) )
		$line .= "    (F-$this->m_fileName)";
		if (!empty($this->m_lineNumber) )
		$line .= "    (#-$this->m_lineNumber)";
		$line .= "\n";
		$this->writeLineToFile($this->get_levelFileName(), $line);
	}
	/**
	* get the full file name for a level
	* @access 	private
	* @return 	string
	* @author 	Rolf Wessels rolfdw[at]gmail.com
	**/
	function get_levelFileName()
	{
		$fileName= "";
		switch ($this->m_level) {
			case CLOG_DEBUG:
				$fileName .= CLOG_LOG_FILE_DEBUG;
				break;
			case CLOG_NOTICE:
				$fileName .= CLOG_LOG_FILE_NOTICE;
				break;
			case CLOG_WARNING:
				$fileName .= CLOG_LOG_FILE_WARNING;
				break;
			case CLOG_ERROR:
				$fileName .= CLOG_LOG_FILE_ERROR;
				break;
			default:
				$fileName .= CLOG_LOG_FILE_ERROR;
		}
		return CLOG_LOG_FILE_PATH.$fileName;
	}			
	
	/**
	* Writes a line to a file also makes sure that the file does not exceed 1 Meg in size
	* @param 	$inFileName
	* @param 	$inLine
	* @access 	private
	* @return 	void
	* @author 	Rolf Wessels rolfdw[at]gmail.com
	**/
	function writeLineToFile($inFileName,$inLine)
	{
		$handle = fopen($inFileName, "a");
	    fputs($handle,$inLine);
		fclose($handle);
		//////////////////////
		// check the file size > if it is over a meg leave only a last 2000 lines
		if (filesize($inFileName)  > (1*1024*1024))
		{
			$file = file($inFileName);
			$handle = fopen($inFileName, "w");
			for ($k = (count($file)-2000) ; $k < count($file) ; $k++)
			{
				fputs($handle,$file[$k]);
			}
			fputs($handle,$in_line);
			fclose($handle);
		}
	
	}
	/**
	* This function will email the error to set recipients
	* @access 	private
	* @return 	void
	* @author 	Rolf Wessels rolfdw[at]gmail.com
	**/
	function email_error()
	{
		$line = date(CLOG_DEFAULT_DATETIME_FORMAT)." : *** ".str_pad($this->get_levelName(),8);
		$line .= $this->m_lastErrorString;
		
		if (!empty($this->m_fileName) )
		$line .= "    (F-$this->m_fileName)";
		if (!empty($this->m_lineNumber) )
		$line .= "    (#-$this->m_lineNumber)";
		$line .= "\n";
		
		////////////////////
		// This is just an example. I would suggest you overite this function
		// and use the nice class provided by Brent R. Matzelle  http://www.phpclasses.org/browse/package/264.html
	
		$send_to = CLOG_SEND_EMAIL_TO;
		$subject = "Error on website";
		$message = "The following error has occured:\n\n $line";
		mail($send_to,$subject,$message);
	}
	/****************************************************************************************
	* Get Set Functions 
	*****************************************************************************************/
	/**
	* get the level name
	* @access 	public
	* @return 	string
	* @author 	Rolf Wessels rolfdw[at]gmail.com
	**/
	function get_levelName()
	{
		$type= "";
		switch ($this->m_level) {
			case CLOG_DEBUG:
				$type .= "DEBUG";
				break;
			case CLOG_NOTICE:
				$type .= "NOTICE";
				break;
			case CLOG_WARNING:
				$type .= "WARNING";
				break;
			case CLOG_ERROR:
				$type .= "ERROR";
				break;
			default:
				$type .= "OTHER";
		}
		return $type;
	}
	/**
	* Get the variable m_lastErrorString
	* @return string m_lastErrorString
	**/
	function get_lastErrorString()
	{
		return $this->m_lastErrorString;
	}
	
	/**
	* Set variable m_lastErrorString
	* @param string in_lastErrorString
	**/
	function set_lastErrorString($in_lastErrorString)
	{
		$this->m_lastErrorString = $in_lastErrorString;
	}
	/**
	* Get the variable m_lineNumber
	* @return int m_lineNumber
	**/
	function get_lineNumber()
	{
		return $this->m_lineNumber;
	}
	
	/**
	* Set variable m_lineNumber
	* @param int in_lineNumber
	**/
	function set_lineNumber($in_lineNumber)
	{
		$this->m_lineNumber = $in_lineNumber;
	}
	/**
	* Get the variable m_fileName
	* @return string m_fileName
	**/
	function get_fileName()
	{
		return $this->m_fileName;
	}
	
	/**
	* Set variable m_fileName
	* @param string in_fileName
	**/
	function set_fileName($in_fileName)
	{
		$this->m_fileName = $in_fileName;
	}
	/**
	* Get the variables m_level
	* @return int m_level
	**/
	function get_level()
	{
		return $this->m_level;
	}
	
	/**
	* Set variable m_level
	* @param int in_level
	**/
	function set_level($in_level)
	{
		$this->m_level = $in_level;
	}
	
	
} // end of class definition Clog

if (defined('CLOG_OVERRIDE_ERROR_HANDLER') && CLOG_OVERRIDE_ERROR_HANDLER)
{
	set_error_handler("ClogErrorHandler");
}
function ClogErrorHandler($errno, $errstr, $errfile, $errline) 
{
  $errortype = array (
            E_ERROR           => "Error",
            E_WARNING         => "Warning",
            E_PARSE           => "Parsing Error",
            E_NOTICE          => "Notice",
            E_CORE_ERROR      => "Core Error",
            E_CORE_WARNING    => "Core Warning",
            E_COMPILE_ERROR   => "Compile Error",
            E_COMPILE_WARNING => "Compile Warning",
            E_USER_ERROR      => "User Error",
            E_USER_WARNING    => "User Warning",
            E_USER_NOTICE     => "User Notice"
            );
  
  switch ($errno) 
  {
	  case E_ERROR:
	    Clog::error( $errstr, $errfile, $errline);
	    break;
	  case E_NOTICE:
	    Clog::notice( $errstr, $errfile, $errline);
	    break;
	  case E_WARNING:
	    Clog::warning( $errstr, $errfile, $errline);
	    break;
	  default:
	  	Clog::error( $errortype[$errno]." ".$errstr, $errfile, $errline);
  }
}

?>
